package cn.baiweigang.uu.strategy.linearswap;

import cn.baiweigang.uu.model.KLineInfo;
import cn.baiweigang.uu.model.StrategyInfo;
import cn.baiweigang.uu.model.TradeInfo;
import cn.baiweigang.uu.service.*;
import cn.baiweigang.uu.service.linearswap.*;
import cn.baiweigang.uu.strategy.BaseStrategy;
import cn.baiweigang.uu.utils.DateUtil;
import cn.baiweigang.uu.utils.LogUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

@Service
public class Min5Strategy extends BaseStrategy {

    //策略配置
    //最低开仓账户余额，默认20USD
    private BigDecimal openLowBalance = BigDecimal.valueOf(10);

    /**
     * 开仓参数配置
     */
    //开仓同步下单的止盈点数
    private int tp = 500;
    //开仓同步下单的止损点数
    private int sl = 1000;
    //开仓委托单成交最大等待时间
    private int waitOpenMaxMinutes = 1;//1分钟

    /**
     * 平仓参数配置
     */
    //盈利配置
    private int[][] tpN = {
            {30, 200, -1},
            {30, 100, 10},

            {10, 300, -1},
            {10, 200, 10},

            {0, 400, -1},
            {0, 300, 10},
            {0, 200, 30},
    };
    //亏损配置 xx分钟后 盈利>=xx点 并且反向趋势分>=xx
    private int[][] slN = {
            {30, 200, -1},
            {30, 100, 10},

            {10, 200, 30},
            {10, 100, 50},

            {0, 300, -1},
            {0, 200, 50},
            {0, 100, 70},
    };
    // xx分钟后 曾亏损大于xx 目前盈利>=xx点 立即平仓
    private int[][] tpIfslN = {
            {0, -200, 100},
            {0, -100, 200},
            {0, -50, 300},
    };
    // xx分钟后 动态止损配置
    private int[][] slDynamic = {
            {0, 450, 400},//1分钟后 当前盈亏=450 动态设置止损价 触发则盈利=350
            {0, 400, 350},
            {0, 350, 300},
            {0, 300, 250},
            {0, 250, 150},
            {0, 200, 50},
//            {0, 150, 50},
    };

    //持仓最大时间 2小时
    private int positionMaxMinutes = 60;
    //5分钟内最大变化点数 触发强平 1000点
    private int changeMaxVolume = 1000;
    //开仓最低趋势分数
    private int openScore = 70;//开仓分数
    //当前有订单成交，允许下次委托下单时间 16分钟后
    private int closeAndOpenMinutes = 11;
    //当天允许最大亏损点数 如果达到后，当天暂停开仓并报警
    private int day1SlMaxVolume = -2000;

    //服务
    @Autowired
    private DbService dbService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private KLineService kLineService;
    @Autowired
    private UpOrDownService upOrDownService;
    @Autowired
    private StrategyService strategyService;
    @Autowired
    private RiskService riskService;
    @Autowired
    private GuardService guardService;

    @Override
    public boolean init() {
        if (!super.init()) {
            return false;
        }
        //记录下一次开仓时间
        long allowNextOpenTs = 0;
        if (strategyInfo != null) allowNextOpenTs = strategyInfo.getAllowNextOpenTs();
        //TODO 1 账号可用性检查，包括计算开仓合约张数
        if (!accountService.check(accountInfo)) {
            LogUtil.logError("账号不可用 无法开始交易");
            return false;
        }
        //TODO 2 检查委托单情况  如果有撤单
        orderService.cancelIfExist(accountInfo);
        //TODO 3 检查持仓情况，如果有强平
        orderService.forceIfExist(accountInfo);
        //TODO 4 初始化策略
        strategyInfo = strategyService.init(accountInfo);
        //设置允许的下一次开仓时间
        strategyInfo.setAllowNextOpenTs(allowNextOpenTs);
        //TODO 5 给策略设置配置
        setConfigForStrategy();
        LogUtil.logInfo("准备工作完成，新的一轮开始");
        return true;
    }

    @Override
    public void acceptTrade(TradeInfo tradeInfo) {
        //收到订单信息
        LogUtil.logInfo("收到订单变化信息");
        LogUtil.logInfo(tradeInfo);
        switch (tradeInfo.getStatus()) {
            case ALL_DEAL://成交
                strategyService.orderAllDeal(strategyInfo, tradeInfo);
                break;
            case SUBMITED://已提交成功
                strategyService.orderSubmited(strategyInfo, tradeInfo);
                break;
            default:
                LogUtil.logInfo("此状态的订单推送 暂不处理");
                break;
        }
    }

    @Override
    public void priceChange(KLineInfo kLineInfo) {
        //自动化守护检查
        guardService.checkAutoAvailable(strategyInfo);
        //收到价格变化信息
        LogUtil.logInfo("\r\n*****************************************");
        LogUtil.logInfo("收到价格变化信息 报价= " + kLineInfo.getClose() +
                " 当前策略状态= " + strategyInfo.getCurrentStrategyStatus().getCode());
        //更新到K线图列表
        kLineService.updateToKList(strategyInfo.getKLineList(), kLineInfo);
        //更新趋势分
        upOrDownService.updateScore(strategyInfo);

        LogUtil.logInfo("当前策略状态=" + strategyInfo.getCurrentStrategyStatus().getCode());
        switch (strategyInfo.getCurrentStrategyStatus()) {
            case INIT:
                LogUtil.logInfo("准备开仓");
                strategyService.submitOpenOrder(strategyInfo, kLineInfo);
                break;
            case WAIT_TO_OPEN:
                LogUtil.logInfo("需要重新提交开仓委托单");
                strategyService.submitOpenOrder(strategyInfo, kLineInfo);
                break;
            case EXIST_OPEN_ORDER:
                LogUtil.logInfo("当前存在开仓委托单");
                strategyService.checkOpenOrder(strategyInfo, kLineInfo);
                break;
            case OPEN_ORDER_DEAL:
//                LogUtil.logInfo("当前持仓中 当前报价=" + kLineInfo.getClose().intValue());
                //持仓风险检查
                riskService.checkRiskForPosition(strategyInfo, kLineInfo);
                //持仓策略处理
                strategyService.checkPosition(strategyInfo, kLineInfo);
                break;
            case WAIT_TO_CLOSE:
                LogUtil.logInfo("准备提交平仓委托单");
                strategyService.submitCloseOrder(strategyInfo, kLineInfo);
                break;
            case EXIST_CLOSE_ORDER:
                LogUtil.logInfo("当前存在平仓委托单");
                strategyService.checkCloseOrder(strategyInfo, kLineInfo);
                break;
            case CLOSE_ORDER_DEAL:
                LogUtil.logInfo("平仓委托单已全部成交");
                strategyService.endRound(strategyInfo);
                LogUtil.logInfo("订单信息写入DB");
                dbService.insertOrderHistory(strategyInfo);
                break;
            case END:
                //获取最新汇总信息
                strategyInfo.setSummarySheetInfo(
                        dbService.queryDay1(accountInfo, DateUtil.formatDateYMD()));
                riskService.checkRiskAfterEnd(strategyInfo);
                LogUtil.logInfo("新的一轮开始，重新初始化");
                init();
                break;
            default:
                LogUtil.logError("策略状态不在处理范围内 " + strategyInfo.getCurrentStrategyStatus());
                break;
        }

    }

    /**
     * 获取策略信息
     *
     * @return
     */
    @Override
    public StrategyInfo getStrategy() {
        return strategyInfo;
    }

    private void setConfigForStrategy() {
        //设置配置信息
        strategyInfo.setTp(tp);
        strategyInfo.setSl(sl);
        strategyInfo.setOpenScore(openScore);
        strategyInfo.setWaitOpenMaxMinutes(waitOpenMaxMinutes);
        strategyInfo.setTpN(tpN);
        strategyInfo.setSlN(slN);
        strategyInfo.setTpIfslN(tpIfslN);
        strategyInfo.setSlDynamic(slDynamic);
        strategyInfo.setCloseAndOpenMinutes(closeAndOpenMinutes);

        strategyInfo.setPositionMaxMinutes(positionMaxMinutes);
        strategyInfo.setChangeMaxVolume(changeMaxVolume);
        strategyInfo.setDay1SlMaxVolume(day1SlMaxVolume);
    }

}
